using DG.Tweening;
using Gameplay.PVE.Data;
using Gameplay.PVE.Utils;
using NpcFramework;
using System;
using System.Collections.Generic;
using Gameplay.PVE.Config;
using UnityEngine;
using Yoozoo.Framework.Managers;
using Yoozoo.Gta.Common;
using Yoozoo.Managers;
using Random = UnityEngine.Random;

namespace Gameplay.PVE.Entity
{
    public class UnitManager
    {
        private static UnitManager instance;

        public List<UnitBase> units = new List<UnitBase>();
        private int unitId;
        private int vehicleCount;
        private List<ObstacleUnit> obstacles = new List<ObstacleUnit>();
        public List<NpcUnit> npcUnits = new List<NpcUnit>();

        public int enemyDeadNum;
        private int killNum;

        public int KillNum => killNum;

        //存放不同阵营队伍的引用，用于索敌
        private Dictionary<int,List<BattleUnit>> teamUnits = new Dictionary<int, List<BattleUnit>>();

        private List<UnitBase> selfDeadUnits = new List<UnitBase>();

        private List<Vector3> hidePoints = new List<Vector3>();
        private List<Vector3> attackPoints = new List<Vector3>();
        private List<Vector3> configAttackPoints = new List<Vector3>();
        
        private Dictionary<GameObject,int> specialObjectDic = new Dictionary<GameObject, int>();
        private List<int> specialSpawnDelayCalls = new List<int>();

        private Dictionary<int, Dictionary<int, GameObject>> summonObjectDic = new Dictionary<int, Dictionary<int, GameObject>>();

        public int globalSkillIndex;

        private List<BattleUnit> enemyAutoSkillList = new List<BattleUnit>();
        private int currentAutoSkillPriority;
        public float enemyEnergy;
        
        
        public static UnitManager Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new UnitManager();
                }
                return instance;
            }
        }

        public void Pause()
        {
            for (int i = 0; i < units.Count; i++)
            {
                if (units[i] is BattleUnit unit)
                {
                    unit.Pause();
                }
            }
        }

        public void Resume()
        {
            for (int i = 0; i < units.Count; i++)
            {
                if (units[i] is BattleUnit unit)
                {
                    unit.Resume();
                }
            }
        }

        
        public void LogicPause()
        {
            foreach (var teamList in teamUnits.Values)
            {
                for (int i = 0; i < teamList.Count; i++)
                {
                    teamList[i].Data.isLogicPause = true;
                    teamList[i].Transmit(ETransmitType.LogicPause);
                }
            }
        }

       
        private void InitBattleUnit(BattleUnit unit,int index = 0)
        {
            unit.Data.colliderCenter = new Vector3(0, PveUtils.globalRatio, 0);
            unit.Data.colliderSize = new Vector3(PveUtils.globalRatio * 0.7f, PveUtils.globalRatio * 2, PveUtils.globalRatio * 0.7f);
            List<BattleUnit> teamUnits;
            if (!this.teamUnits.TryGetValue(unit.Data.team, out teamUnits))
            {
                teamUnits = new List<BattleUnit>();
                this.teamUnits.Add(unit.Data.team,teamUnits);
            }

            if (unit.Data.team == 0)
            {
                unit.Data.index = teamUnits.Count;
            }
            else
            {
                unit.Data.index = index;
            }
            //PveFindPathManager.Instance.AddUnit(unit);
            unit.Birth();
            if (PveManager.Instance.isInRpg)
            {
                unit.Transmit(ETransmitType.ToRPG);
            }
            else
            {
                unit.Transmit(ETransmitType.ToPve);
            }
            teamUnits.Add(unit);
            var unitBornArg = ClassManager.Get<UnitBornArg>();
            unitBornArg.unit = unit;
            for (int i = 0; i < units.Count; i++)
            {
                units[i].Transmit(ETransmitType.UnitBorn,unitBornArg);
            }
            ClassManager.Free(unitBornArg);
            if (unit.Data.team == 2 && unit.Data.HasSkillInitiative())
            {
                enemyAutoSkillList.Add(unit);
            }
        }

        public void AddToSummonDic(int skillIndex,int unitIndex,GameObject gameObject)
        {
            Dictionary<int, GameObject> summons;
            if (!summonObjectDic.TryGetValue(skillIndex, out summons))
            {
                summons = new Dictionary<int, GameObject>();
                summonObjectDic[skillIndex] = summons;
            }

            if (summons.ContainsKey(unitIndex))
            {
                Debug.Log("已经存在召唤模型位置"+skillIndex+" "+unitIndex);
            }
            gameObject.transform.SetParent(PveScene.pveRootTrans);
            summons[unitIndex] = gameObject;
        }

        public void RemoveSummonDic(int skillIndex,int summonUnitId)
        {
            if (summonObjectDic.TryGetValue(skillIndex, out var summons))
            {
                foreach (var item in summons.Values)
                {
                    PveResourceManager.RecoverResource(item,PveResourceManager.EPveResType.Model,
                        summonUnitId);
                }
                summons.Clear();
                summonObjectDic.Remove(skillIndex);
            }
        }
        
        public GameObject GetGameObjectFromSummonDic(int skillIndex,int unitIndex)
        {
            GameObject obj = null;
            if (summonObjectDic.TryGetValue(skillIndex, out var summons))
            {
                if (summons.TryGetValue(unitIndex, out var go))
                {
                    obj = go;
                    summons.Remove(unitIndex);
                    return obj;
                }
            }
            //Debug.LogError("找不到召唤物模型"+skillIndex+" "+unitIndex);
            return obj;
        }
        
        public UnitBase AddSummonUnit(int heroId,int summonId,int summonIndex,int skillIndex,int team,int stageId,Vector3 position,UnitBase summonParent)
        {
            var data = ClassManager.Get<UnitData>();
            data.isManualMoving = false;
            data.id = unitId;
            data.team = team;
            data.unitType = 0;
            data.searchInfos.Clear();
            data.stage = stageId;
            data.ClearOrders();
            data.birthPosition = position;
            data.hatredDic.Clear();
            data.summonId = summonId;
            data.summonConfig = PveUtils.GetRpgSummonConfig(summonId);
            data.summonParent = summonParent;
            data.summonIndex = summonIndex;
            data.summonSkillIndex = skillIndex;
            data.AddTag((int)EPveUnitTag.summonUnit);
            data.AddTag((int)EPveUnitTag.self);
            data.AddTag((int)EPveUnitTag.parent,summonParent.Data.id);
            data.InitMonsterConfig(heroId);//index);
            var unit = ClassManager.Get<BattleUnit>();
            unit.Initialize(data);
            units.Add(unit);
            unit.Data.isSummonUnit = true;
            InitBattleUnit(unit);
            data.searchInfos.Add(new UnitData.SearchInfo
            {
                searchType = 0,
                searchArg = new Dictionary<string, float>
                {
                    ["Radius"] = data.attackRange,
                    ["Angle"] = 120,
                }
            });
            unitId++;
            return unit;
        }

        public UnitBase AddMyUnit(int heroId,int stageId,int positionId = 0)
        {
            var data = ClassManager.Get<UnitData>();
            data.isManualMoving = PveManager.Instance.isManualMoving && unitId == 0;
            data.id = unitId;
            data.team = 0;
            data.unitType = 0;
            data.searchInfos.Clear();
            data.moveSpeed = 5 * PveUtils.globalRatio;
            data.positionId = positionId;
            data.stage = stageId;
            data.ClearOrders();
            data.hatredDic.Clear();
            data.InitHeroConfig(heroId);//index);
            data.AddTag((int)EPveUnitTag.hero);
            data.AddTag((int)EPveUnitTag.self);
            var unit = ClassManager.Get<BattleUnit>();
            unit.Initialize(data);
            units.Add(unit);
            InitBattleUnit(unit);
            data.searchInfos.Add(new UnitData.SearchInfo
            {
                searchType = 0,
                searchArg = new Dictionary<string, float>
                {
                    ["Radius"] = data.attackRange,
                    ["Angle"] = 120,
                }
            });
            unitId++;
            return unit;
        }

        //我方增援人物
        public UnitBase AddMyMonsterUnit(int heroId,int stageId,int level)
        {
            var data = ClassManager.Get<UnitData>();
            data.isManualMoving = PveManager.Instance.isManualMoving && unitId == 0;
            data.id = unitId;
            data.team = 0;
            data.unitType = 0;
            data.searchInfos.Clear();
            data.moveSpeed = 5 * PveUtils.globalRatio;
            data.stage = stageId;
            data.ClearOrders();
            data.hatredDic.Clear();
            data.InitMonsterConfig(heroId,level);
            var unit = ClassManager.Get<BattleUnit>();
            unit.Initialize(data);
            units.Add(unit);
            data.AddTag((int)EPveUnitTag.hero);
            data.AddTag((int)EPveUnitTag.self);
            InitBattleUnit(unit);
            data.searchInfos.Add(new UnitData.SearchInfo
            {
                searchType = 0,
                searchArg = new Dictionary<string, float>
                {
                    ["Radius"] = data.attackRange,
                    ["Angle"] = 120,
                }
            }); 
            unitId++;
            if (unit.Data.rpgInitiativeSkillConfig != null)
            {
                PveCardManager.Instance.AddSkill(unit);
                TimeManager.Instance.DelayCall(100, () =>
                {
                    unit.SetHpChange(unit.Data.CurrentHp);
                    unit.SetMpChange(unit.Data.CurrentMp);
                });
            }
            return unit;
        }


        private BattleUnit afkUnit;
        
        /// 临时写的 把主角写死成亚瑟
        public UnitBase AddAFKMyUnit(int heroId, int stageId)
        {
            var data = ClassManager.Get<UnitData>();
            data.isManualMoving = PveManager.Instance.isManualMoving && unitId == 0;
            data.id = NpcDataManager.MainCharacterId;
            data.team = 0;
            data.unitType = 0;
            data.searchInfos.Clear();
            data.moveSpeed = 5 * PveUtils.globalRatio;
            data.stage = stageId;
            data.ClearOrders();
            data.hatredDic.Clear();
            //data.InitHeroConfig(heroId);//index);
            data.modelId = 6666;
            var unit = ClassManager.Get<BattleUnit>();
            unit.Initialize(data);
            units.Add(unit);
            InitBattleUnit(unit);
            data.searchInfos.Add(new UnitData.SearchInfo
            {
                searchType = 0,
                searchArg = new Dictionary<string, float>
                {
                    ["Radius"] = data.attackRange,
                    ["Angle"] = 120,
                }
            });
            afkUnit = unit;
            return unit;
        }

        public BattleUnit GetAfkMainUnit()
        {
            return afkUnit;
        }
        public void DynamicCreateObstacle(int summonId,int id, int team, Vector3 position,Vector3 rotation,UnitBase parent,int skillLevel)
        {
            var config = PveUtils.GetRpgObstacleConfig(id);
            var obstacle = new RpgLevelData.RpgObstacle
            {
                id = id,
                obstacleId = (int) config.res_id,
                playerHidePoints = config.hide_points,
                enemyHidePoints = new List<Vector3>(),
                breakId = config.break_res_id,
                height = (int) config.height,
                width = (int) config.width,
                hp = (int) config.hp,
                position = position,
                rotation = Vector3.zero,
                scale = new Vector3(1, 1, 1),
            };
            CreateObstacle(summonId,obstacle,parent,skillLevel);
            var units = GetAllUnitByTeam(team);
            for (int j = 0; j < config.hide_points.Count; j++)
            {
                var hidepoint = config.hide_points[j] / 10000f + position;
                BattleUnit hideUnit = null;
                float distance = float.MaxValue;

                for (int i = 0; i < units.Count; i++)
                {
                    if (units[i].Data.isGoingToHidePoint || units[i].Data.isHiding || !units[i].Data.isCanSquat)
                    {
                        continue;
                    }
                    var d = Vector3.Distance(units[i].Data.position, hidepoint);
                    if (d < distance)
                    {
                        distance = d;
                        hideUnit = units[i];
                    }
                }
                hideUnit?.Transmit(ETransmitType.ObstacleUpdate);
            }

        }

        public void DynamicCreateUnit(int summonId,int id,int summonIndex,int skillIndex,int team,Vector3 position,Vector3 forward,UnitBase parent = null,int skillLevel = 0)
        {
            DynamicCreateBattleUnit(summonId,id,summonIndex,team,skillIndex,position,forward,parent,skillLevel);
        }

        public void DynamicCreateEnemy()
        {
            int stageId = PveManager.Instance.stageId;
            var unit = AddEnemyUnit(100, stageId,0);
            unit.Data.position = PveUtils.GetRandomVector3(new Vector3(-2, 0, -2), new Vector3(2, 0, 2)) + PveManager.Instance.GetStagePosition() + new Vector3(25*stageId + 25,0,0);
            unit.Transmit(ETransmitType.SpawnInStage);
            unit.Transmit(ETransmitType.HideHud);
        }

        public void DynamicCreateBattleUnit(int summonId,int id,int summonIndex,int team,int skillIndex,Vector3 position,Vector3 forward,UnitBase parent,int skillLevel)
        {
            int stageId = PveManager.Instance.stageId;
            var unit = AddSummonUnit(id, summonId,summonIndex,skillIndex,team,stageId,position,parent);
            unit.Data.position = position;
            unit.Data.forward = forward;
            unit.Data.birthPosition = position;
            unit.Data.SetTargetForward(forward);
            unit.Data.CalculateSummonAttribute(parent.Data,skillLevel);
            if (parent != null)
            {
                parent.Data.summonUnit = unit;
            }
            unit.Transmit(ETransmitType.SpawnInStage);
            unit.Transmit(ETransmitType.HideHud);
        }

        public void DynamicCreateSelfHero(int id)
        {
            int stageId = PveManager.Instance.stageId;
            var unit = AddMyUnit(id, stageId);
            //unit.Data.position = PveUtils.GetRandomVector3(new Vector3(-2, 0, -2), new Vector3(2, 0, 2)) + PveManager.Itance.GetStagePosition() + new Vector3(25*stageId + 25,0,0);
            unit.Transmit(ETransmitType.SpawnInStage);
            unit.Transmit(ETransmitType.HideHud);
            unit.Data.moveState = 0;
        }

        public void AddUnitsWithSpecialObject(int specialObjectId,Vector3 position,List<Action<Vector3,float>> addUnitHandler)
        {
            var config = PveUtils.GetRpgSpecialObjectConfig(specialObjectId);
            if (config != null)
            {
                var car = PveResourceManager.GetResource(PveResourceManager.EPveResType.Model,
                    config.model_id);
                car.transform.SetParent(PveScene.pveRootTrans);
                car.SetActive(true);
                car.transform.position = position + config.in_offset;
                specialObjectDic.Add(car,config.model_id);
                if (config.type == 1)//漂移进场
                {
                    car.transform.forward =
                        config.out_offset - config.in_offset;
                    car.transform.DOMove(position, config.in_params[0]).SetEase(Ease.OutQuint);
                    car.transform.DORotate(new Vector3(0, config.in_params[1], 0), 1.6f).SetEase(Ease.OutQuint).SetDelay(0.4f);
                    int delayCallId = TimeManager.Instance.DelayCall((int)(config.in_params[2] * 1000),
                        () =>
                        {
                            if (PveManager.Instance.isInPve)
                            {
                                return;
                            }
                            float myValue = 0;
                            float value = 1;
                            float duration = config.in_params[3];
                            var mats = car.GetComponentInChildren<MeshRenderer>().materials;
                            DOTween.To(() => { return myValue; },
                                (v) =>
                                {
                                    for (int j = 0; j < mats.Length; j++)
                                    {
                                        mats[j].SetFloat("_Alpha",1-v);
                                    }

                                    if (v >= 1)
                                    {
                                        for (int j = 0; j < mats.Length; j++)
                                        {
                                            mats[j].SetFloat("_Alpha",1);
                                        }
                                        PveResourceManager.RecoverResource(car,PveResourceManager.EPveResType.Model,config.model_id);
                                        specialObjectDic.Remove(car);
                                    }
                                }, value, duration);
                        }); 
                    specialSpawnDelayCalls.Add(delayCallId);
                }
                else
                {
                    float moveDuration = Vector3.Distance(config.out_offset,
                                             config.in_offset) /
                                         config.speed;
                    car.transform.forward =
                        config.out_offset - config.in_offset;
                    car.transform.DOMove(position + config.out_offset, moveDuration);
                }
                
                for (int i = 0; i < addUnitHandler.Count; i++)
                {
                    var handler = addUnitHandler[i];
                    int delayCallId = TimeManager.Instance.DelayCall((int)(config.spawn_time[i] * 1000), ()=>
                    {
                        handler.Invoke(car.transform.position,car.transform.localEulerAngles.y);
                    });
                    specialSpawnDelayCalls.Add(delayCallId);
                }
            }
        }

        public UnitBase AddEnemyUnit(int heroId,int stageId,int index,int level = 1,int skillPriority = 0,int skillCd = 0,int skillBornCd = 0,int positionId = 0)
        {
            if (PveGlobalVlues.specificEnemy != 0)
            {
                heroId = PveGlobalVlues.specificEnemy;
            }
            var data = ClassManager.Get<UnitData>();
            data.id = unitId;
            data.team = 2;
            data.unitType = 0;
            data.autoSkillPriority = skillPriority;
            data.autoSkillCd = skillCd;
            data.autoSkillBornCd = skillBornCd;
            data.searchInfos.Clear();
            data.searchInfos.Add(new UnitData.SearchInfo
            {
                searchType = 1,
                searchArg = new Dictionary<string, float>
                {
                    ["Radius"] = data.searchRange,
                    //["Angle"] = 120,
                }
            });
            data.isDraggable = false;
            data.moveSpeed = 6 * PveUtils.globalRatio;
            data.stage = stageId;
            data.ClearOrders();
            data.hatredDic.Clear();
            data.InitMonsterConfig(heroId,level);
            data.AddTag((int)EPveUnitTag.hero);
            data.AddTag((int)EPveUnitTag.self);
            var unit = ClassManager.Get<BattleUnit>();
            unit.Initialize(data);
            units.Add(unit);
            InitBattleUnit(unit,index);
            unitId++;
            //data.SetTargetForward(Vector3.left);
            unit.Data.positionId = PveUtils.GetPositionIdByDeckIndex(positionId);
            return unit;
        }

        public void CreateObstacle(int id,RpgLevelData.RpgObstacle obstacle,UnitBase parent, int skillLevel = 0)
        {
            var stageId = PveManager.Instance.stageId;
            var data = ClassManager.Get<UnitData>();
            data.id = unitId + 100000;
            data.team = parent.Data.team;
            data.unitType = 3;
            data.stage = stageId;
            data.modelId = obstacle.obstacleId;
            data.deadModelId = obstacle.breakId;
            data.summonId = id;
            var size = PveUtils.GetObstacleSize(obstacle.obstacleId);
            data.colliderCenter = new Vector3(0, size.y / 2, 0);
            data.colliderSize = size;
            data.CurrentHp = obstacle.hp;
            data.TotalHp = obstacle.hp;
            data.hidePositions.Clear();
            data.summonParent = parent;
            data.AddTag((int)EPveUnitTag.obstacle);
            data.AddTag((int)EPveUnitTag.self);
            data.AddTag((int)EPveUnitTag.parent,parent.Data.id);
            var playerHidePoints = new List<Vector3>();
            for (int i = 0; i < obstacle.playerHidePoints.Count; i++)
            {
                playerHidePoints.Add(obstacle.playerHidePoints[i] / 10000f + obstacle.position);
            }
            data.hidePositions.Add(0,playerHidePoints);
            var enemyHidePoints = new List<Vector3>();
            for (int i = 0; i < obstacle.enemyHidePoints.Count; i++)
            {
                enemyHidePoints.Add(obstacle.enemyHidePoints[i] + obstacle.position);
            }
            data.hidePositions.Add(2,enemyHidePoints);
            data.obstacleConfig = PveUtils.GetRpgObstacleConfig(obstacle.id);
            var unit = ClassManager.Get<ObstacleUnit>();
            unit.Initialize(data);
            unit.Birth();
            units.Add(unit);
            unit.Data.position = obstacle.position;
            unit.gameObject.transform.position = unit.Data.position;
            unit.gameObject.transform.localEulerAngles = obstacle.rotation;
            unit.Data.InitObstacleData();
            unit.Data.CalculateSummonAttribute(parent.Data,skillLevel);
            PveFindPathManager.Instance.AddObstacle(data.id,unit.Data.position,obstacle,stageId);
            obstacles.Add(unit);
            unitId++;
            AddHidePoint(unit);
            unit.Data.roadType = PveManager.Instance.GetRpgRoadTypeByPosition(unit.Data.position);
             
            var unitBornArg = ClassManager.Get<UnitBornArg>();
            unitBornArg.unit = unit;
            for (int i = 0; i < units.Count; i++)
            {
                units[i].Transmit(ETransmitType.UnitBorn,unitBornArg);
            }
            ClassManager.Free(unitBornArg);
        }

        public void AddObstacle(int stageId,RpgLevelData.RpgObstacle obstacle,Vector3 startPosition)
        {
            var data = ClassManager.Get<UnitData>();
            data.id = unitId + 1000;
            data.team = 3;
            data.unitType = 3;
            data.stage = stageId;
            data.modelId = obstacle.obstacleId;
            data.deadModelId = obstacle.breakId;
            var size = PveUtils.GetObstacleSize(obstacle.obstacleId);
            data.colliderCenter = new Vector3(0, size.y / 2, 0);
            data.colliderSize = size;
            data.CurrentHp = obstacle.hp * 10;
            data.TotalHp = obstacle.hp * 10;
            data.hidePositions.Clear();
            var playerHidePoints = new List<Vector3>();
            for (int i = 0; i < obstacle.playerHidePoints.Count; i++)
            {
                playerHidePoints.Add(obstacle.playerHidePoints[i] + startPosition);
            }
            data.hidePositions.Add(0,playerHidePoints);
            var enemyHidePoints = new List<Vector3>();
            for (int i = 0; i < obstacle.enemyHidePoints.Count; i++)
            {
                enemyHidePoints.Add(obstacle.enemyHidePoints[i] + startPosition);
            }
            data.hidePositions.Add(2,enemyHidePoints);
            var unit = ClassManager.Get<ObstacleUnit>();
            unit.Initialize(data);
            unit.Birth();
            units.Add(unit);
            unit.Data.position = obstacle.position + startPosition;
            unit.gameObject.transform.position = unit.Data.position;
            unit.gameObject.transform.localEulerAngles = obstacle.rotation;
            PveFindPathManager.Instance.AddObstacle(data.id,unit.Data.position,obstacle,stageId);
            obstacles.Add(unit);
            unitId++;
            foreach (var list in teamUnits.Values)
            {
                for (int i = 0; i < list.Count; i++)
                {
                    if (Vector3.Distance(list[i].Data.position, unit.Data.position) < 3)
                    {
                        var targetPosition = PveFindPathManager.Instance.GetPointByObstacle(list[i].Data.id,list[i].Data.position,list[i].Data.position);
                        var a = ClassManager.Get<AddOrderTransmitArg>();
                        a.order = ClassManager.Get<UnitOrder>();
                        a.order.type = UnitOrder.EOrderType.MoveToPosition;
                        a.order.targetPosition = targetPosition;
                        list[i].Transmit(ETransmitType.AddOrder,a);
                    }
                }
            }
            AddHidePoint(unit);
           
        }

        public MortalUnit AddMortal(int unitId, int stageId,int modelId,bool specialNpc = false)
        {
            var data = ClassManager.Get<UnitData>();
            data.id = unitId;
            data.team = 1;
            data.unitType = 1;
            data.hasBattleInSight = false;
            data.searchInfos.Clear();
            data.searchInfos.Add(new UnitData.SearchInfo
            {
                searchType = 1,
                searchArg = new Dictionary<string, float>
                {
                    ["Radius"] = data.searchRange,
                }
            });
            data.modelId = modelId;
            data.stage = stageId;
            data.ClearOrders();
            data.hatredDic.Clear();
            var unit = ClassManager.Get<MortalUnit>();
            if (specialNpc)
            {
                unit.SpecialNpc = true;
            }
            unit.Initialize(data);
            unit.Birth();
            units.Add(unit);
            unitId++;
            return unit;

        }

        public void AddNpc(int unitId,int stageId)
        {
            var data = ClassManager.Get<UnitData>();
            data.id = unitId;
            data.team = 3;
            data.unitType = 4;
            data.hasTriggerdSpecialCase = false;
            data.searchInfos.Clear();
            /*data.searchInfos.Add(new UnitData.SearchInfo
            {
                searchType = 1,
                searchArg = new Dictionary<string, float>
                {
                    ["Radius"] = data.searchRange,
                }
            });*/
            data.modelId = 2003;
            data.stage = stageId;
            data.ClearOrders();
            data.hatredDic.Clear();
            var unit = ClassManager.Get<NpcUnit>();
            unit.Initialize(data);
            unit.Birth();
            units.Add(unit);
            npcUnits.Add(unit);
        }

        public void AddVehicle(int stageId)
        {
            var data = ClassManager.Get<UnitData>();
            data.id = unitId;
            data.team = 1;
            data.unitType = 2;
            data.searchInfos.Clear();
            data.searchInfos.Add(new UnitData.SearchInfo
            {
                searchType = 2,
                searchArg = new Dictionary<string, float>
                {
                    ["Distance"] = data.searchRange,
                }
            });
            data.modelId = 600;
            data.angleSpeed = 120;
            data.stage = stageId;
            data.ClearOrders();
            data.hatredDic.Clear();
            var unit = ClassManager.Get<VehicleUnit>();
            unit.Initialize(data);
            unit.Birth();
            units.Add(unit);
            vehicleCount++;
            unitId++;
        }

        public void RemoveUnit(int id)
        {
            for (int i = 0; i < units.Count; i++)
            {
                if (units[i].Data.id == id)
                {
                    ClassManager.Free(units[i]);
                    units.RemoveAt(i);
                    return;
                }
            }
        }

        public void UnitDead(int id)
        {
            Vector3 deadPosition = Vector3.zero;
            int team = -1;
            bool isNormalUnitDead = false;
            for (int i = 0; i < units.Count; i++)
            {
                if (units[i].Data.id == id)
                {
                    if (units[i] is BattleUnit battleUnit)
                    {
                        PveFindPathManager.Instance.RemoveUnit(battleUnit);
                        OperationManager.Instance.UnitDead((battleUnit));
                        if (battleUnit.Data.team == 2 && battleUnit.Data.attackPosition != Vector3.zero)
                        {
                            attackPoints.Add(battleUnit.Data.attackPosition);
                            battleUnit.Data.attackPosition = Vector3.zero;
                        }

                        if (!battleUnit.Data.isSummonUnit)
                        {
                            isNormalUnitDead = true;
                        }

                        if (battleUnit.Data.team == 2 && battleUnit.Data.HasSkillInitiative())
                        {
                            enemyAutoSkillList.Remove(battleUnit);
                        }

                        if (battleUnit.Data.team == 2)
                        {
                            RemoveStageSpawnUnit(battleUnit.Data.enemyStage, battleUnit.Data.enemyIndex);
                        }
                    }

                    if (units[i] is VehicleUnit)
                    {
                        vehicleCount--;
                        ClassManager.Free(units[i]);
                        units.RemoveAt(i);
                        break;
                    }
                    deadPosition = units[i].Data.position;
                    //ClassManager.Free(units[i]);
                    team = units[i].Data.team;
                    if (team == 2)
                    {
                        enemyDeadNum++;
                    }
                    else if (team == 0 && !units[i].Data.isSummonUnit)
                    {
                        selfDeadUnits.Add(units[i]);
                    }
                    if (units[i] is ObstacleUnit obs)
                    {
                        for (int j = 0; j < hidePoints.Count; j++)
                        {
                            foreach (var item in obs.Data.hidePositions.Values)
                            {
                                for (int k = 0; k < item.Count; k++)
                                {
                                    if (hidePoints[j] == item[k])
                                    {
                                        hidePoints.RemoveAt(j);
                                        j--;
                                    }
                                }
                            }
                        }
                        
                        obstacles.Remove(obs);
                        PveFindPathManager.Instance.RemoveObstacle(units[i].Data.id);
                        //units.RemoveAt(i);
                        //ClassManager.Free(units[i]);
                        //units.RemoveAt(i);
                    }
                    //units.RemoveAt(i);
                    break;
                }
            }

            var teamList = GetAllUnitByTeam(team);
            for (int i = 0; i < teamList.Count; i++)
            {
                if (teamList[i].Data.id == id)
                {
                    teamList.RemoveAt(i);
                    break;
                }
            }

            if (isNormalUnitDead)
            {
                var arg = ClassManager.Get<NormalUnitDeadArg>();
                arg.team = team;
                for (int i = 0; i < units.Count; i++)
                {
                    units[i].Transmit(ETransmitType.NormalUnitDead,arg);
                }
                ClassManager.Free(arg);
            }


            if (!PveManager.Instance.IsStageActive)
            {
                return;
            }
            
            if (PveManager.Instance.isInRpg)
            {
                if (team == 0)
                {
                    CheckIsSelfAllDead();
                }
                else
                {
                    killNum++;
                    ResidentHandler.Inst.GetFunction("pveManager.UpdateKillNum").Action(killNum);
                    CheckIsEnemyAllDead();
                }
            }
            else
            {
                if (team == 2)
                {
                    int money = (int)(1000 * Random.Range(0.8f,1.2f));
                    //PveFlyTextManager.Instance.ShowFlyTextMoney("$ +" + money, deadPosition,0.5f);
                    //PveManager.Instance.ShowDropMoneyFly(Data.position);
                    /*for (int i = 0; i < count; i++)
                    {
                        PveManager.Instance.SpawnItem(deadPosition, PveDropType.Money, 1);
                    }*/

                    //PveManager.Instance.SpawnUIFlyItem(deadPosition, PveDropType.Money, count);

                    /*var random = Random.Range(0, 1f);
                    if (random < 0.3f)
                    {
                        PveManager.Instance.SpawnItem(deadPosition,PveDropType.BulletBag,1);
                    }
                    else if (random < 0.6f)
                    {
                        PveManager.Instance.SpawnItem(deadPosition,PveDropType.MedicBag,1);
                    }*/

                    CheckIsEnemyAllDead();
                }
            }
        }

        public List<BattleUnit> GetAllUnitByTeam(int team)
        {
            List<BattleUnit> units;
            if (!teamUnits.TryGetValue(team, out units))
            {
                units = new List<BattleUnit>();
                teamUnits.Add(team,units);
            }

            return units;
        }

        private void CheckIsSelfAllDead()
        {
            var list = GetAllUnitByTeam(0);
            if (list.Count == 0 && ResidentHandler.Inst.GetFunction("L_RpgManager.IsSelfAllSpawn").Func<int,bool>(0))
            {
                
            }
            /*
            var unit = GetUnit(0);
            if (unit.Data.isDead)
            {
                PveManager.Instance.RpgLose();
            }*/
        }

        private void CheckIsEnemyAllDead()
        {
            var list = GetAllUnitByTeam(2);
            bool isEnemyAllSpawn = ResidentHandler.Inst.GetFunction("L_RpgManager.IsEnemyAllSpawn").Func<int,bool>(0);//PveManager.Instance.CheckIsEnemyAllSpawn();
            if (list.Count == 0 && isEnemyAllSpawn)
            {
                if (PveManager.Instance.isInPve)
                {
                    
                }
                else
                {
                    
                }
            }
        }

        public bool IsUnitDying()
        {
            for (int i = 0; i < units.Count; i++)
            {
                if (units[i] is BattleUnit bu && bu.Data.isDying)
                {
                    Debug.Log("waiting for " + bu.Data.id + " dying");
                    return true;
                }
            }
            return false;
        }
        
        public int GetMyTeamRandomHeroID()
        {
            var list = new List<int>(this.units.Count);
            for (var i = 0; i < this.units.Count; i++)
            {
                if (!(this.units[i] is BattleUnit))
                    continue;
                
                var d = this.units[i].Data;
                if ( d.isSummonUnit || d.team != 0)
                    continue;
                
                list.Add(d.heroId);
            }

            if (list.Count == 0)
                return -1;

            return list[Random.Range(0, list.Count)];
        }

        private class StageSpawn
        {
            public List<int> units;
            public float stageStartTime;
        }
        private Dictionary<int,StageSpawn> stageSpawns = new Dictionary<int, StageSpawn>();

        public float GetStageStartTime(int stage)
        {
            if (this.stageSpawns.TryGetValue(stage, out var stageStartTime))
            {
                return stageStartTime.stageStartTime;
            }
            return -1;
        }

        public void ResetStageStartTime()
        {
            stageSpawns.Clear();
            currentStage = 0;
            restEnemyCount = 0;
            maxStage = 0;
        }
        
        public int restEnemyCount;
        public int currentStage;
        public int maxStage;
        
        public void UpdateWaveUI()
        {
            ResidentHandler.Inst.GetFunction("pveManager.UpdateWave").Action(currentStage + 1, maxStage + 1);
        }

        public void UpdateAliveEnemyUI()
        {
            ResidentHandler.Inst.GetFunction("pveManager.UpdateAliveEnemy").Action(restEnemyCount);
        }
        
        public void RemoveStageSpawnUnit(int stage, int index)
        {
            if (stageSpawns.TryGetValue(stage, out var ss))
            {
                if (ss.units.Remove(index))
                {
                    restEnemyCount--;
                }
                if (ss.units.Count == 0 && currentStage == stage)
                {
                    currentStage++;
                    UpdateWaveUI();
                    if (stageSpawns.TryGetValue(currentStage, out var sss))
                    {
                        sss.stageStartTime = PveManager.Instance.stageActiveTime;
                    }
                }
            }
            UpdateAliveEnemyUI();
        }

        public void AddStageSpawnUnit(int stage,int index)
        {
            StageSpawn ss;
            if (!stageSpawns.TryGetValue(stage, out ss))
            {
                ss = new StageSpawn();
                ss.units = new List<int>();
                stageSpawns[stage] = ss;
                if (maxStage < stage)
                {
                    maxStage = stage;
                }
            }
            stageSpawns[stage].units.Add(index);
            restEnemyCount++;
        }

        public void UpdateStageSpawnTime(int stage, float time)
        {
            if (stageSpawns.TryGetValue(stage, out var ss))
            {
                ss.stageStartTime = time;
            }
        }

        public List<ObstacleUnit> GetObstacles()
        {
            return obstacles;
        }

        public void UnitLeaveHidePoint(Vector3 position)
        {
            //Debug.LogError("add " + position);
            hidePoints.Add(position);
        }

        public void UnitInHidePoint(Vector3 position)
        {
            //Debug.LogError("remove " + position);
            hidePoints.Remove(position);
        }

        public List<Vector3> GetHidePositions(int stageId)
        {
            return hidePoints;
        }

        public void RefreshAttackPointsTest()
        {
            configAttackPoints.Clear();
            var center = PveManager.Instance.GetRpgStageCenterPosition();
            /*for (int i = -2; i <= 2; i++)
            {
                for (int j = 0; j <= 2; j++)
                {
                    var position = new Vector3(4 + j * 3, 0, i * 3) + center + PveUtils.GetRandomVector3(new Vector3(-1,0,-1), new Vector3(1,0,1));
                    configAttackPoints.Add(position);
                }
            }*/
            
            var levelConfig = PveUtils.GetRpgLevelMonsterConfig(PveManager.Instance.RpgLevelId);
            if (levelConfig != null)
            {
                var modelId = levelConfig.model_id;
                var configs = PveUtils.GetRpgModelPlaceConfigs(modelId);
                foreach (var item in configs.Values)
                {
                    if (item.type == 1)
                    {
                        configAttackPoints.Add(center + item.place_pos);
                    }
                }
            }
            attackPoints.Clear();
            for (int i = 0; i < configAttackPoints.Count; i++)
            {
                if (!PveFindPathManager.Instance.CheckIsOutOfBound(configAttackPoints[i]))
                {
                    attackPoints.Add(configAttackPoints[i]);
                }
                else
                {
                    //Debug.LogWarning("进攻点超出了地图边界 "+configAttackPoints[i]);
                }
            }
        }

        private GameObject attackPointRoot;
        
        public void ShowAttackPoints()
        {
            if (attackPointRoot == null)
            {
                attackPointRoot = new GameObject("[AttackPoint]");
                attackPointRoot.transform.position = PveManager.Instance.GetRpgStageCenterPosition();
                for (int i = 0; i < configAttackPoints.Count; i++)
                {
                    var obj = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                    obj.GetComponent<Collider>().enabled = false;
                    obj.transform.position = configAttackPoints[i];
                    obj.transform.SetParent(attackPointRoot.transform);
                }
            }
            else
            {
                attackPointRoot.SetActive(!attackPointRoot.activeSelf);
                attackPointRoot.transform.position = PveManager.Instance.GetRpgStageCenterPosition();
            }
        }

        private bool showAttackRange;
        public void ShowAttackRange()
        {
            showAttackRange = !showAttackRange;
            for (int i = 0; i < units.Count; i++)
            {
                if (showAttackRange)
                {
                    units[i].Transmit(ETransmitType.ShowAttackRange);
                }
                else
                {
                    units[i].Transmit(ETransmitType.HideAttackRange);
                }
            }
        }

        public void RefreshHidePointsTest()
        {
            /*float id = 100;
            float hp = 100000;
            float width = 4;
            float height = 4;
            float breakId = 0;

            var position = PveManager.Instance.GetRpgStageCenterPosition() + new Vector3(-3, 0, -7);
            var angle = new Vector3(0, 40, 0);
            var obstacle = new RpgLevelData.RpgObstacle
            {
                obstacleId = (int) id,
                playerHidePoints = new List<Vector3> {new Vector3(-2, 0, 0)},
                enemyHidePoints = new List<Vector3>(),
                breakId = (int) breakId,
                height = (int) height,
                width = (int) width,
                hp = (int) hp,
                position = position,
                rotation = angle,
                scale = new Vector3(1, 1, 1),
            };
            CreateObstacle(obstacle);

            position = PveManager.Instance.GetRpgStageCenterPosition() + new Vector3(-2, 0, 7);
            angle = new Vector3(0, -40, 0);
            obstacle = new RpgLevelData.RpgObstacle
            {
                obstacleId = (int) id,
                playerHidePoints = new List<Vector3> {new Vector3(-2, 0, 0)},
                enemyHidePoints = new List<Vector3>(),
                breakId = (int) breakId,
                height = (int) height,
                width = (int) width,
                hp = (int) hp,
                position = position,
                rotation = angle,
                scale = new Vector3(1, 1, 1),
            };
            CreateObstacle(obstacle);*/
        }

        public int GetAllUnitCountByTeam(int team)
        {
            int count = 0;
            for (int i = 0; i < units.Count; i++)
            {
                if (units[i].Data.team == team)
                {
                    count++;
                }
            }

            return count;
        }

        public Vector3 GetMeleeAttackPosition()
        {
            return attackPoints[Random.Range(0, attackPoints.Count)];
        }
        
        /// <summary>
        /// 找到能攻击到目标的离自己最近的AttackPoint
        /// </summary>
        /// <param name="attacker"></param>
        /// <returns></returns>
        public Vector3 GetAttackPositionNew(UnitBase attacker)
        {
            if (attacker.Data.lockTarget == null)
            {
                return Vector3.zero;
            }

            if (attacker.Data.attackPosition != Vector3.zero)
            {
                attackPoints.Add(attacker.Data.attackPosition);
            }
            var targetPosition = attacker.Data.position;
            var distance = float.MaxValue;
            var candidate = Vector3.zero;
            var index = -1;
            for (int i = 0; i < attackPoints.Count; i++)
            {
                if (Vector3.Distance(attackPoints[i], attacker.Data.lockTarget.Data.position) >
                    attacker.Data.attackRange)
                {
                    continue;
                }

                /*if (Vector3.Distance(attackPoints[i], attacker.Data.birthPosition) < 0.01f && Vector3.Distance(attacker.Data.birthPosition,attacker.Data.position) < 0.01f)
                {
                    candidate = attacker.Data.birthPosition;
                    index = i;
                    break;
                }*/
                var d = Vector3.Distance(attackPoints[i],targetPosition);
                /*if (attackPoints[i].x > PveGlobalVlues.SelfMeleeLine)
                {
                    d += (attackPoints[i].x - PveGlobalVlues.SelfMeleeLine) * 2;
                }*/
                if (d < distance)
                {
                    candidate = attackPoints[i];
                    distance = d;
                    index = i;
                }
            }

            if (index == -1)
            {
                return Vector3.zero;
            }

            //如果合出生点相差不大，就直接用这个attackPoint
            if (Vector3.Distance(attacker.Data.attackPosition, attacker.Data.birthPosition) < 0.1f)
            {
                attacker.Data.attackPosition = attacker.Data.birthPosition;
            }
            else
            {
                attacker.Data.attackPosition = candidate;
            }
            
            attackPoints.RemoveAt(index);
            return candidate;
        }

        public Vector3 GetAttackPosition(UnitBase attacker, int stageId, Vector3 position)
        {
            if (attacker.Data.lockTarget == null)
            {
                return attacker.Data.targetPosition;
            }
            attacker.Data.hidePosition = Vector3.zero;
            Vector3 candidate = attacker.Data.lockTarget.Data.position;
            ObstacleUnit wall = null;
            for (int i = 0; i < units.Count; i++)
            {
                var unit = units[i];
                if (unit is ObstacleUnit wallUnit && unit.Data.roadType == attacker.Data.roadType)
                {
                    if (unit.Data.hidingUnit == attacker)
                    {
                        unit.Data.hidingUnit = null;
                    }

                    if (unit.Data.hidingUnit == null)
                    {
                        var hidePositions = unit.Data.hidePositions[attacker.Data.team];
                        for (int j = 0; j < hidePositions.Count; j++)
                        {
                            if (position == hidePositions[j])
                            {
                                unit.Data.hidingUnit = attacker;
                                if (Vector3.Distance(position, attacker.Data.position) > attacker.Data.attackRange)
                                {
                                    attacker.Data.SetLockTarget(null);
                                }

                                if (attacker.Data.hidingObstacle != wallUnit)
                                {
                                    attacker.Data.LeaveHidePoint();
                                    attacker.Data.hidingObstacle = wallUnit;
                                }
                                attacker.Data.hidePosition = position;
                                return position;
                            }
                        }
                    }
                }
            }

            return Vector3.zero;
        }

        public Vector3 GetAttackPosition(UnitBase attacker,int stageId)
        {
            if (!attacker.Data.isCanSquat)
            {
                return Vector3.zero;
            }
            /*if (attacker.Data.lockTarget == null)
            {
                return Vector3.zero;
            }*/

            attacker.Data.hidePosition = Vector3.zero;
            Vector3 candidate = attacker.Data.position;
            if (attacker.Data.lockTarget != null)
            {
                candidate = attacker.Data.lockTarget.Data.position;
            }
            Vector3 targetPosition = candidate;
            ObstacleUnit wall = null;
            float minDistance = Vector3.Distance(candidate, attacker.Data.position);
            for (int i = 0; i < units.Count; i++)
            {
                var unit = units[i];
                if (unit is ObstacleUnit wallUnit && unit.Data.stage == stageId && !unit.Data.isDead)
                {
                    if (unit.Data.hidingUnit == attacker)
                    {
                        unit.Data.hidingUnit = null;
                    }

                    if (unit.Data.hidingUnit == null)
                    {
                        var hidePositions = unit.Data.hidePositions[attacker.Data.team];
                        for (int j = 0; j < hidePositions.Count; j++)
                        {
                            var hidePosition = hidePositions[j];
                            float distance = Vector3.Distance(targetPosition, hidePosition);
                            if (distance <= attacker.Data.attackRange || true)
                            {
                                var currentDistance = Vector3.Distance(hidePosition, attacker.Data.position);

                                if (currentDistance < minDistance) ;// && currentDistance < 7)
                                {
                                    minDistance = currentDistance;
                                    candidate = hidePosition;
                                    wall = wallUnit;
                                }
                            }
                        }

                    }
                }
            }

            if (wall != null)
            {
                attacker.Data.hidePosition = candidate;
                attacker.Data.readyTohideObstacle = wall;
                wall.Data.hidingUnit = attacker;
            }
            else
            {
                candidate = Vector3.zero;
            }
            /*else
            {
                if (attacker.Data.isInStageAttackPosition)
                {
                    attacker.Data.isInStageAttackPosition = false;
                    rpgAttackPositions.Add(attacker.Data.stageAttackPosition);
                }
                int index = -1;
                for (int i = 0; i < rpgAttackPositions.Count; i++)
                {
                    var d = Vector3.Distance(attacker.Data.lockTarget.Data.position, rpgAttackPositions[i]);
                    if (d <= attacker.Data.attackRange)
                    {
                        var currentDistance = Vector3.Distance(rpgAttackPositions[i], attacker.Data.position);
                        if (currentDistance < minDistance)
                        {
                            minDistance = currentDistance;
                            candidate = rpgAttackPositions[i];
                            index = i;
                        }
                    }
                }

                if (index != -1)
                {
                    attacker.Data.stageAttackPosition = rpgAttackPositions[index];
                    rpgAttackPositions.RemoveAt(index);
                    attacker.Data.isInStageAttackPosition = true;
                }

                if (attacker.Data.team == 2)
                {
                    //Debug.LogError(attacker.Data.id + " " + candidate + " " + index);
                }
            }*/
            return candidate;
        }

        public void ResLoadComplete()
        {
            for (int i = 0; i < units.Count; i++)
            {
                units[i].OtherResourceComplete();
            }
        }

        public void Restart()
        {
            for (int i = 0; i < units.Count; i++)
            {
                units[i].Transmit(ETransmitType.SkillForceStop);
            }
        }

        public void StageStart()
        {
            selfDeadUnits.Clear();
            for (int i = 0; i < units.Count; i++)
            {
                units[i].Transmit(ETransmitType.StageStart);
            }
        }

        private void AddHidePoint(ObstacleUnit unit)
        {
            if (unit.Data.hidePositions.TryGetValue(0, out var points))
            {
                for (int i = 0; i < points.Count; i++)
                {
                    hidePoints.Add(points[i]);
                }
            }

        }

        public void ClearSummonUnit()
        {
            var removeList = new List<UnitBase>();
            for (int i = 0; i < units.Count; i++)
            {
                var unit = units[i];
                if (unit.Data.isSummonUnit)
                {
                    removeList.Add(unit);
                    UnitDead(unit.Data.id);
                    units.RemoveAt(i);
                    i--;
                }
            }

            for (int i = 0; i < removeList.Count; i++)
            {
                ClassManager.Free(removeList[i]);
            }
        }

        public void ClearObstacles()
        {
            var removeList = new List<UnitBase>();
            for (int i = 0; i < units.Count; i++)
            {
                var unit = units[i];
                if (unit is ObstacleUnit)
                {
                    removeList.Add(unit);
                }
            }
            
            for (int i = 0; i < removeList.Count; i++)
            {
                UnitDead(removeList[i].Data.id);
                units.Remove(removeList[i]);
                ClassManager.Free(removeList[i]);
            }
            
        }

        public void ClearHangingUnits()
        {
            for (int i = 0; i < units.Count; i++)
            {
                var unit = units[i];
                if (unit is MortalUnit)
                {
                    ClassManager.Free(unit);
                    units.RemoveAt(i);
                    i--;
                }
            }
        }

        public void RpgStart(bool isStart = false)
        {
            globalSkillIndex = 1;
            hidePoints.Clear();
            for (int i = 0; i < obstacles.Count; i++)
            {
                AddHidePoint(obstacles[i]);
            }

            ClearSummonUnit();
            for (int i = 0; i < units.Count; i++)
            {
                units[i].Transmit(ETransmitType.RPGStart);
            }

            if (isStart)
            {
                killNum = 0;
                ResidentHandler.Inst.GetFunction("pveManager.UpdateKillNum").Action(killNum);
            }

            enemyEnergy = PveGlobalVlues.InitTeamEnergy;
        }

        public void StartGoToRpg()
        {
            var list = GetAllUnitByTeam(2);
            //var cameraPosition = PveCameraManager.Instance.GetCameraFocusPosition();
            for (int i = 0; i < units.Count; i++)
            {
                if (units[i].Data.team != 2)
                {
                    continue;
                }
                //var distance = Vector3.Distance(units[i].Data.position, cameraPosition);
                if (/*distance < 20 &&*/ !units[i].Data.isDead)
                {
                    units[i].Dead();
                }
                else
                {
                    var unit = units[i];
                    units.RemoveAt(i);
                    for (int j = 0; j < list.Count; j++)
                    {
                        if (list[j].Data.id == unit.Data.id)
                        {
                            list.RemoveAt(j);
                            break;
                        }
                    }
                    ClassManager.Free(unit);
                    i--;
                }
            }
        }

        public void ClearLastStageUnits(int stageId)
        {
            var removeList = new List<UnitBase>();
            for (int i = 0; i < units.Count; i++)
            {
                if (units[i].Data.team != 0 && (units[i].Data.stage < stageId || units[i].Data.isDead))
                {
                    removeList.Add(units[i]);
                    //ClassManager.Free(units[i]);
                    units.RemoveAt(i);
                    i--;
                }
            }

            var list = GetAllUnitByTeam(2);
            for (int i = 0; i < list.Count; i++)
            {
                if (removeList.Contains(list[i]))
                {
                    list.RemoveAt(i);
                    i--;
                }
            }

            for (int i = 0; i < removeList.Count; i++)
            {
                ClassManager.Free(removeList[i]);
            }
        }

        public UnitBase GetUnitIgnoreType(int id)
        {
            var unit = GetUnit(id);
            if (unit != null)
            {
                return unit;
            }

            var obstacle = PveManager.Instance.GetObstacleUnit(id);
            if (obstacle != null)
            {
                return obstacle;
            }

            return null;
        }
        
        public BattleUnit GetUnit(int id)
        {
            for (int i = 0; i < units.Count; i++)
            {
                if (units[i].Data.id == id)
                {
                    return units[i] as BattleUnit;
                }
            }

            return null;
        }

        public UnitBase GetUnitBase(int id)
        {
            for (int i = 0; i < units.Count; i++)
            {
                if (units[i].Data.id == id)
                {
                    return units[i];
                }
            }

            return null;
        }
        public MortalUnit GetMortalUnit(int id)
        {
            for (int i = 0; i < units.Count; i++)
            {
                if (units[i].Data.id == id)
                {
                    return units[i] as MortalUnit;
                }
            }

            return null;
        }

        public ObstacleUnit GetObstacleUnit(int id)
        {
            for (int i = 0; i < units.Count; i++)
            {
                if (units[i].Data.id == id && !units[i].Data.isDead)
                {
                    return units[i] as ObstacleUnit;
                }
            }

            return null;
        }

        public void Update()
        {
            for (int i = 0; i < units.Count; i++)
            {
                units[i].Update();
                /*if (!units[i].Data.isDead && units[i] is BattleUnit)
                {
                    PveManager.Instance.UpdateMiniMapUnitPosition(units[i]);
                }*/
            }

            enemyEnergy += PveGlobalVlues.EnemyEnergyRecoverSpeed * TimeManager.LogicDeltaTime;
            if (enemyEnergy > 10)
            {
                enemyEnergy = 10;
            }
            UpdateEnemyAutoSkillPriority();
        }

        public void FixedUpdate()
        {
            for (int i = 0; i < units.Count; i++)
            {
                units[i].FixedUpdate();
            }
        }

        public void BeforeUpdate()
        {
            for (int i = 0; i < units.Count; i++)
            {
                units[i].BeforeUpdate();
            }
        }

        public void LateUpdate()
        {
            for (int i = 0; i < units.Count; i++)
            {
                units[i].LateUpdate();
            }
        }

        //每帧调用，检测当前释放技能的优先级
        private void UpdateEnemyAutoSkillPriority()
        {
            int highestPriority = -1;
            int currentPriority = -1;
            for (int i = 0; i < enemyAutoSkillList.Count; i++)
            {
                var unit = enemyAutoSkillList[i];
                if (!unit.Data.isDead)
                {
                    int p = unit.Data.autoSkillPriority;
                    if (!unit.Data.hasAutoUsedSkill && !unit.Data.IsSkillInCD())
                    {
                        if (p > currentPriority)
                        {
                            currentPriority = p;
                        }
                    }

                    if (p > highestPriority)
                    {
                        highestPriority = p;
                    }
                }
            }

            //这一轮已经全部放完了，需要刷新
            if (currentPriority == -1)
            {
                for (int i = 0; i < enemyAutoSkillList.Count; i++)
                {
                    var unit = enemyAutoSkillList[i];
                    if (!unit.Data.isDead)
                    {
                        unit.Data.hasAutoUsedSkill = false;
                    }
                }
                currentPriority = highestPriority;
            }
            currentAutoSkillPriority = currentPriority;
        }

        public bool CheckIsCanAutoSkill(UnitData data)
        {
            bool energyEnough = data.rpgSkillCost <= enemyEnergy;
            bool readyToCast = data.autoSkillPriority == currentAutoSkillPriority;
            if (PveGlobalVlues.UseHeroMp)
            {
                energyEnough = data.CurrentMp >= data.mpCost;
                readyToCast = true;
                data.hasAutoUsedSkill = false;
            }
            if (data.HasSkillInitiative()  && !data.hasAutoUsedSkill && readyToCast && energyEnough && !data.IsSkillInCD())
            {
                return true;
            }
            return false;
        }
        

        public void ClearStage()
        {
            unitId = 0;
            for (int i = 0; i < units.Count; i++)
            {
                ClassManager.Free(units[i]);
            }
            selfDeadUnits.Clear();
            units.Clear();
            obstacles.Clear();
            teamUnits.Clear();
            npcUnits.Clear();
            enemyAutoSkillList.Clear();
            
            foreach (var item in specialObjectDic)
            {
                PveResourceManager.RecoverResource(item.Key,PveResourceManager.EPveResType.Model,item.Value);
            }
            specialObjectDic.Clear();
            for (int i = 0; i < specialSpawnDelayCalls.Count; i++)
            {
                TimeManager.Instance.CancelDelayCall(specialSpawnDelayCalls[i]);
            }
            specialSpawnDelayCalls.Clear();
                   
        }

        public void ClearMyHeroes()
        {
            for (int i = 0; i < units.Count; i++)
            {
                var unit = units[i];
                if (unit.Data.team == 0)
                {
                    ClassManager.Free(unit);
                    units.RemoveAt(i);
                    i--;
                }
            }
            unitId = 0;
            selfDeadUnits.Clear();
            var team = GetAllUnitByTeam(0);
            team.Clear();
            PveManager.Instance.mainUnit = null;
        }

        public void ClearEnemy()
        {
            var removeList = new List<UnitBase>();
            for (int i = 0; i < units.Count; i++)
            {
                var unit = units[i];
                if (unit.Data.team == 2)
                {
                    removeList.Add(unit);
                    UnitDead(unit.Data.id);
                    units.RemoveAt(i);
                    i--;
                }
            }

            for (int i = 0; i < removeList.Count; i++)
            {
                ClassManager.Free(removeList[i]);
            }

            /*var team = GetAllUnitByTeam(2);
            team.Clear();*/
        }

        public void HideAllHeroes()
        {
            for (int i = 0; i < units.Count; i++)
            {
                units[i].Hide();
            }
        }

        public void ShowAllHeroes()
        {
            for (int i = 0; i < units.Count; i++)
            {
                units[i].Show();
            }
        }

        public void StageEnd()
        {
            for (int i = 0; i < units.Count; i++)
            {
                units[i].Transmit(ETransmitType.StageEnd);
            }
        }

        public void SwitchBall()
        {
            for (int i = 0; i < units.Count; i++)
            {
                units[i].Transmit(ETransmitType.SwitchBall);
            }
        }
        
        public void RebornSelfUnits()
        {
            selfDeadUnits.Sort((a, b) => a.Data.id.CompareTo(b.Data.id));
            var team = GetAllUnitByTeam(0);
            for (int i = 0; i < selfDeadUnits.Count; i++)
            {
                selfDeadUnits[i].Transmit(ETransmitType.Reborn);
                team.Add(selfDeadUnits[i] as BattleUnit);
            }
            team.Sort((a, b) => a.Data.id.CompareTo(b.Data.id));
        }

        public void Dispose()
        {
            unitId = 0;
            for (int i = 0; i < units.Count; i++)
            {
                ClassManager.Free(units[i]);
            }
            units.Clear();
            obstacles.Clear();
            teamUnits.Clear();
            npcUnits.Clear();
            instance = null;
            
            var handler = ResidentHandler.Inst;
            if(handler == null) return;
            handler.RemoveFunction("pveManager.UpdateKillNum");
            handler.RemoveFunction("L_RpgManager.IsSelfAllSpawn");
            handler.RemoveFunction("L_RpgManager.IsEnemyAllSpawn");
            handler.RemoveFunction("pveManager.UpdateWave");
            handler.RemoveFunction("pveManager.UpdateAliveEnemy");
            handler.RemoveFunction("pveManager.UpdateKillNum");
        }
    }
}
